use wasm_bindgen::prelude::*;

/// 判断一个点是否在矩形框内
///
/// 算法：点的x坐标在矩形框的x和x+w之间，且点的y坐标在矩形框的y和y+h之间
///
/// # Arguments
///
/// * `px` - 点的x坐标
/// * `py` - 点的y坐标
/// * `x` - 矩形框的x坐标
/// * `y` - 矩形框的y坐标
/// * `w` - 矩形框的宽度
/// * `h` - 矩形框的高度
///
/// # Returns
///
/// * `true` - 点在矩形框内
/// * `false` - 点不在矩形框内
///
#[wasm_bindgen]
pub fn point_in_rect(
    px: f64,
    py: f64,
    x: f64,
    y: f64,
    w: f64,
    h: f64,
) -> bool {
    let x1 = x + w;
    let y1 = y + h;
    (px >= x && px <= x1) && (py >= y && py <= y1)
}

/// 判断一个线段是否在矩形框内
///
/// 算法：线段的2个端点都在矩形框内
///
/// # Arguments
///
/// * `x1` - 线段的x坐标1
/// * `y1` - 线段的y坐标1
/// * `x2` - 线段的x坐标2
/// * `y2` - 线段的y坐标2
/// * `x` - 矩形框的x坐标
/// * `y` - 矩形框的y坐标
/// * `w` - 矩形框的宽度
/// * `h` - 矩形框的高度
///
/// # Returns
///
/// * `true` - 线段在矩形框内
/// * `false` - 线段不在矩形框内
///
#[wasm_bindgen]
pub fn line_in_rect(
  x1: f64,
  y1: f64,
  x2: f64,
  y2: f64,
  x: f64,
  y: f64,
  w: f64,
  h: f64,
) -> bool {
  let p1_in_rect = point_in_rect(x1, y1, x, y, w, h);
  let p2_in_rect = point_in_rect(x2, y2, x, y, w, h);
  p1_in_rect && p2_in_rect
}

/// 检测线和线是否相交
///
/// 算法：
/// 1. 计算两条线的斜率
/// 2. 如果斜率相同，则两条线平行，不相交
/// 3. 如果斜率不同，则两条线相交
/// 4. 计算交点
/// 5. 判断交点是否在两条线的范围内
///
/// 参考:
/// https://stackoverflow.com/questions/9043805/test-if-two-lines-intersect-javascript-function
///
/// # Arguments
///
/// * `x1` - 线段的x坐标1
/// * `y1` - 线段的y坐标1
/// * `x2` - 线段的x坐标2
/// * `y2` - 线段的y坐标2
/// * `x3` - 线段的x坐标3
/// * `y3` - 线段的y坐标3
/// * `x4` - 线段的x坐标4
/// * `y4` - 线段的y坐标4
///
/// # Returns
///
/// * `true` - 线段相交
/// * `false` - 线段不相交
///
#[wasm_bindgen]
pub fn line_line_intersect(
  x1: f64,
  y1: f64,
  x2: f64,
  y2: f64,
  x3: f64,
  y3: f64,
  x4: f64,
  y4: f64,
) -> bool {
  let det = (x2 - x1) * (y4 - y3) - (x4 - x3) * (y2 - y1);
  if det < 1e-6 && det > -1e-6 { // determinant is zero
    return false;
  }

  let lambda = ((y4 - y3) * (x4 - x1) + (x3 - x4) * (y4 - y1)) / det;
  let gamma = ((y1 - y2) * (x4 - x1) + (x2 - x1) * (y4 - y1)) / det;

  (lambda > 0.0 && lambda < 1.0) && (gamma > 0.0 && gamma < 1.0)
}

/// 检测线和矩形是否相交
///
/// 算法: 检查线是否与矩形的任一边相交，如果相交则返回true
///
/// # Arguments
///
/// * `x1` - 线段的x坐标1
/// * `y1` - 线段的y坐标1
/// * `x2` - 线段的x坐标2
/// * `y2` - 线段的y坐标2
/// * `rx` - 矩形的x坐标
/// * `ry` - 矩形的y坐标
/// * `rw` - 矩形的宽度
/// * `rh` - 矩形的高度
///
/// # Returns
///
/// * `true` - 线段相交
/// * `false` - 线段不相交
///
#[wasm_bindgen]
pub fn line_rect_intersect(
  x1: f64,
  y1: f64,
  x2: f64,
  y2: f64,
  rx: f64,
  ry: f64,
  rw: f64,
  rh: f64,
) -> bool {
  let left = line_line_intersect(x1, y1, x2, y2, rx, ry, rx, ry + rh);
  if left {
    return true;
  }

  let right = line_line_intersect(x1, y1, x2, y2, rx + rw, ry, rx + rw, ry + rh);
  if right {
    return true;
  }

  let top = line_line_intersect(x1, y1, x2, y2, rx, ry, rx + rw, ry);
  if top {
    return true;
  }

  let bottom = line_line_intersect(x1, y1, x2, y2, rx, ry + rh, rx + rw, ry + rh);
  if bottom {
    return true;
  }

  return false;
}

/// 检测线是否在矩形中，或者与矩形相交
///
/// 算法：
/// 1. 判断线是否在矩形中
/// 2. 判断线是否与矩形相交
/// 3. 如果线在矩形中，或者与矩形相交，则返回true
/// 4. 否则返回false
///
/// # Arguments
///
/// * `x1` - 线段的x坐标1
/// * `y1` - 线段的y坐标1
/// * `x2` - 线段的x坐标2
/// * `y2` - 线段的y坐标2
/// * `rx` - 矩形的x坐标
/// * `ry` - 矩形的y坐标
/// * `rw` - 矩形的宽度
/// * `rh` - 矩形的高度
///
/// # Returns
///
/// * `true` - 线段在矩形内或者与矩形相交
/// * `false` - 线段不在矩形内且不与矩形相交
///
#[wasm_bindgen]
pub fn line_in_rect_or_intersect(
  x1: f64,
  y1: f64,
  x2: f64,
  y2: f64,
  rx: f64,
  ry: f64,
  rw: f64,
  rh: f64,
) -> bool {
  let in_rect: bool = line_in_rect(x1, y1, x2, y2, rx, ry, rw, rh);
  if in_rect {
    return true;
  }

  let intersect: bool = line_rect_intersect(x1, y1, x2, y2, rx, ry, rw, rh);
  if intersect {
    return true;
  }

  return false;
}

/// 判断两个矩形是否相交
///
/// 算法：
/// 1. 判断第一个矩形的每个顶点是否在第二个矩形中
/// 2. 如果第一个矩形的每个顶点都在第二个矩形中，则返回true
/// 3. 否则返回false
///
/// # Arguments
///
/// * `min_ax` - 第一个矩形的左边界
/// * `min_ay` - 第一个矩形的上边界
/// * `max_ax` - 第一个矩形的右边界
/// * `max_ay` - 第一个矩形的下边界
/// * `min_bx` - 第二个矩形的左边界
/// * `min_by` - 第二个矩形的上边界
/// * `max_bx` - 第二个矩形的右边界
/// * `max_by` - 第二个矩形的下边界
///
/// # Returns
///
/// * `true` - 两个矩形相交
/// * `false` - 两个矩形不相交
///
#[wasm_bindgen]
pub fn rectangles_intersect(
    min_ax: f64,
    min_ay: f64,
    max_ax: f64,
    max_ay: f64,
    min_bx: f64,
    min_by: f64,
    max_bx: f64,
    max_by: f64,
) -> bool {
    let a_left_of_b = max_ax < min_bx;
    let a_right_of_b = min_ax > max_bx;
    let a_above_b = min_ay > max_by;
    let a_below_b = max_ay < min_by;

    !(a_left_of_b || a_right_of_b || a_above_b || a_below_b)
}

/// 判断第一个矩形是否在第二个矩形中
///
/// 算法：
/// 1. 判断第一个矩形的每个顶点是否在第二个矩形中
/// 2. 如果第一个矩形的每个顶点都在第二个矩形中，则返回true
/// 3. 否则返回false
///
/// # Arguments
///
/// * `min_ax` - 第一个矩形的左边界
/// * `min_ay` - 第一个矩形的上边界
/// * `max_ax` - 第一个矩形的右边界
/// * `max_ay` - 第一个矩形的下边界
/// * `min_bx` - 第二个矩形的左边界
/// * `min_by` - 第二个矩形的上边界
/// * `max_bx` - 第二个矩形的右边界
/// * `max_by` - 第二个矩形的下边界
///
/// # Returns
///
/// * `true` - 第一个矩形在第二个矩形内
/// * `false` - 第一个矩形不在第二个矩形内
///
#[wasm_bindgen]
pub fn rectangle_inside(
  min_ax: f64,
  min_ay: f64,
  max_ax: f64,
  max_ay: f64,
  min_bx: f64,
  min_by: f64,
  max_bx: f64,
  max_by: f64,
) -> bool {
  let p1x = min_ax;
  let p1y = min_ay;
  let p2x = max_ax;
  let p2y = min_ay;
  let p3x = max_ax;
  let p3y = max_ay;
  let p4x = min_ax;
  let p4y = max_ay;

    let x = min_bx;
    let y = min_by;
    let w = max_bx - min_bx;
    let h = max_by - min_by;

    let p1_in_rect = point_in_rect(p1x, p1y, x, y, w, h);
    let p2_in_rect = point_in_rect(p2x, p2y, x, y, w, h);
    let p3_in_rect = point_in_rect(p3x, p3y, x, y, w, h);
    let p4_in_rect = point_in_rect(p4x, p4y, x, y, w, h);

    p1_in_rect && p2_in_rect && p3_in_rect && p4_in_rect
}

